﻿using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;

namespace CzfSDK
{
	/// <summary>
	/// 对象池(线程安全)
	/// </summary>
	public class ConcurrentCzfPool<T>
	{
		Func<T> createFunc;
		Action<T> removeFun;
		int max;
		ConcurrentQueue<T> queue;  				 // 资源队列
		int timeout;
		int currentCount;

		public bool throwException = true;

		/// <summary>
		/// Initializes a new instance of the <see cref="CzfSDK.CzfPool`1"/> class.
		/// </summary>
		/// <param name="createFunc">Create func.</param>
		/// <param name="init">Init.</param>
		/// <param name="max">Max.</param>
		/// <param name="timeout">Timeout.</param>
		protected void Init(Func<T> createFunc, Action<T> removeFun, int init, int max, int timeout)
		{
			LogicTool.AssertNotNull (createFunc);
			LogicTool.AssertNotNull (removeFun);
			LogicTool.Assert (init > 0);
			LogicTool.Assert (timeout > 0);
			LogicTool.Assert (max >= init);

			this.timeout = timeout;
			this.createFunc = createFunc;
			this.removeFun = removeFun;
			this.max = max;
			this.currentCount = init;
			queue = new ConcurrentQueue<T> ();
			for (var i = 0; i < init; i++) {
				queue.Enqueue (createFunc ());
			}
		}

		protected T Create()
		{
			var item = this.createFunc ();
			queue.Enqueue (item);
			return item;
		}

		public bool Exec(Action<T> action)
		{
			return Exec (action, this.timeout);
		}
		public bool Exec(Action<T> action, int timeout)
		{
			LogicTool.AssertNotNull (action);
			T t = default(T);
			try {
				int time = 0;
				while(true){
					if(queue.TryDequeue(out t)){
						break;
					} else if(currentCount < max){
						t = createFunc();
						currentCount++;
						break;
					}
					
					ThreadTool.TaskDelay(100);
					time += 100;
					if (time > timeout){
						if(throwException)
							throw new Exception("超时!!!");
						return false;
					}
				}
				action(t);
				return true;
			} catch(Exception e){
				if (t != null && !t.Equals (default(T))) {
					removeFun (t);
					t = createFunc ();
				}
				throw e;
			} finally {
				if(t != null && !t.Equals(default(T)))
					queue.Enqueue (t);
			}
		}
	}
}

